package com.expect.admin.busmanagement.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.expect.admin.busmanagement.data.dao.BusRepository;
import com.expect.admin.busmanagement.data.dataobject.Bus;
import com.expect.admin.busmanagement.service.vo.BusVo;
import com.expect.admin.data.dao.AttachmentRepository;
import com.expect.admin.data.dao.LcjdbRepository;
import com.expect.admin.data.dao.LcrzbRepository;
import com.expect.admin.data.dao.RoleRepository;
import com.expect.admin.data.dao.UserRepository;
import com.expect.admin.data.dataobject.Attachment;
import com.expect.admin.data.dataobject.Department;
import com.expect.admin.data.dataobject.Lcjdb;
import com.expect.admin.data.dataobject.Lcrzb;
import com.expect.admin.data.dataobject.Role;
import com.expect.admin.data.dataobject.User;
import com.expect.admin.exception.BaseAppException;
import com.expect.admin.service.LcService;
import com.expect.admin.service.LcrzbService;
import com.expect.admin.service.RoleJdgxbGxbService;
import com.expect.admin.service.UserService;
import com.expect.admin.service.vo.AttachmentVo;
import com.expect.admin.service.vo.LcrzbVo;
import com.expect.admin.service.vo.RoleJdgxbGxbVo;
import com.expect.admin.service.vo.UserVo;
import com.expect.admin.utils.DateUtil;
import com.expect.admin.utils.StringUtil;
import com.googlecode.ehcache.annotations.Cacheable;
import com.googlecode.ehcache.annotations.TriggersRemove;

@Service
public class BusService {
	

	
	@Autowired
	private BusRepository busRepository;
	@Autowired
	private UserService userService;
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private LcService lcService;
	@Autowired
	private LcrzbService lcrzbService;
	@Autowired
	private LcrzbRepository lcrzbRepository;
	@Autowired
	private LcjdbRepository lcjdbRepository;
	@Autowired
	private RoleJdgxbGxbService roleJdgxbGxbService;
	@Autowired
	private RoleRepository roleRepository;
	@Autowired
	private AttachmentRepository attachmentRepository;
	
	@Transactional
	public String save(BusVo busVo, String[] attachmentId){
		Bus bus = new Bus(busVo);
		UserVo userVo = userService.getLoginUser();
		User user = userRepository.findOne(userVo.getId());
		bus.setUserName(user);
		
		/**
		 * 处理维保申请和附件的对应关系
		 */
		if(attachmentId != null && attachmentId.length > 0){
			List<Attachment> attachmentList = attachmentRepository.findByIdIn(attachmentId);
			if(attachmentList != null && attachmentList.size() > 0){
				bus.setAttachments(new HashSet<>(attachmentList));
			}
		}else{
			bus.setAttachments(new HashSet<>());
		}
		bus = busRepository.save(bus);
		return bus.getId();
	}
	
	/**
	 * 新维保申请的保存
	 * @param busVo
	 * @param saveWay   保存种类（提交：“submit”，保存：“save”）
	 * @param attachmentId
	 */
	@Transactional
	public void newApplicationSave(BusVo busVo, String saveWay, String[] attachmentId){
		String applicationClassify = getApplicationClassify();
		busVo.setApplicationClassify(applicationClassify);
		String lcbs = applicationClassify;
		String condition = getNewBusCondition(saveWay,lcbs);
		busVo.setApplicationStatement(condition);//申请审核状态
		busVo.setLcbs(lcbs);//流程标识
		if(StringUtil.equals(saveWay, "submit")){
			busVo.setApplicationDate(DateUtil.format(new Date(), DateUtil.fullFormat));
		}
		String id = save(busVo,attachmentId);
		busVo.setId(id);
		if(StringUtil.equals(saveWay, "submit")){
			addXzLcrz(id,busVo.getApplicationClassify(),lcService.getStartCondition(lcbs));//如果是新增就增加一条日志记录
		}
	}

	/**
	 * 新增时增加流程日志
	 * @param id
	 * @param applicationClassify
	 * @param applicationState
	 */
	@Transactional
	public void addXzLcrz(String id,String applicationClassify,String applicationState) {
		LcrzbVo lcrzbVo = new LcrzbVo("新增","");
		String lcrzId = lcrzbService.save(lcrzbVo, id, applicationClassify, applicationState);
		bindBusWithLcrz(id,lcrzId);	
	}

	/**
	 * 流程日志与维保申请的绑定
	 * @param id
	 * @param lcrzId
	 */
	public void bindBusWithLcrz(String BusNo, String lcrzId) {
		Bus bus = busRepository.findOne(BusNo);//
		Lcrzb lcrz = lcrzbRepository.findOne(lcrzId);
		bus.getLcrzSet().add(lcrz);
		busRepository.save(bus);
	}

	private String getNewBusCondition(String saveWay, String lcbs) {
		
		String startCondition = lcService.getStartCondition(lcbs);
		if(!StringUtil.equals(saveWay, "submit")){
			return startCondition;
		}
		else{
			return lcService.getNextCondition(lcbs, startCondition);
		}

	}

	/**
	 * 申请分类
	 * @return
	 */
	private String getApplicationClassify() {//需改
		RoleJdgxbGxbVo roleJdgxbGxbVo= roleJdgxbGxbService.getWjzt("application", "wb");
		Role role = roleRepository.findOne(roleJdgxbGxbVo.getRoleId());
		if(StringUtil.equals(role.getName(), "集团驾驶员")) return "1";//集团申请
		if(StringUtil.equals(role.getName(), "东交公司驾驶员")) return "3";//东交公司申请
		return "2";//非集团申请
	}

	@Transactional
	public void updateApplication(BusVo busVo, String[] attachmentId) {
		if(busVo == null || StringUtil.isBlank(busVo.getId())){
			throw new BaseAppException("要更新的申请Id为空，无法更新");
		}
		Bus bus = busRepository.findOne(busVo.getId());
		if(bus == null){
			throw new BaseAppException("要更新的申请不存在！");
		}
		update(bus,busVo);
		//更新申请的附件列表
		if(attachmentId != null && attachmentId.length > 0){
			List<Attachment> attachmentList = attachmentRepository.findByIdIn(attachmentId);
			if(attachmentList != null && attachmentList.size() > 0){
				bus.setAttachments(new HashSet<>(attachmentList));
			}
		}
		busRepository.save(bus);
	}

	private void update(Bus bus, BusVo busVo) {
		BeanUtils.copyProperties(busVo, bus);
		if(!StringUtils.isBlank(busVo.getApplicationDate())){
			bus.setApplicationDate(DateUtil.parse(busVo.getApplicationDate(), DateUtil.zbFormat));
		}
	}

	/**
	 * 删除申请（软删除）
	 * @param id
	 */
	@Transactional
	public void deleteApplication(String id) {
		Bus bus = busRepository.findById(id);
		if(bus == null){
			throw new BaseAppException("未找到要删除的申请 车辆id为" + id);
		}
		bus.setIsDeleted("Y");
		busRepository.save(bus);
	}

	public BusVo getBusById(String busId) {
		Bus bus = busRepository.findOne(busId);
		if(bus == null){
			throw new BaseAppException("id为"+busId+"的申请记录没找到！");
		}
		BusVo busVo = new BusVo(bus);//申请的基本信息
		List<LcrzbVo> lcrzbVoList = lcrzbService.convert(bus.getLcrzSet());
		Map<String,String> lcjdbMap = getAllLcjdMapping();
		for(LcrzbVo lcrzbVo : lcrzbVoList){
			if(!StringUtil.isBlank(lcrzbVo.getLcjd())){
				String lcjdName = lcjdbMap.get(lcrzbVo.getLcjd());
				lcrzbVo.setLcjd(lcjdName);
			}
		}
//		busVo.setLcrzList(lcrzbService.getKxsLcrzbVoList(busNo));//维保的流程日志信息
		busVo.setLcrzList(lcrzbVoList);
		List<AttachmentVo> attachmentVoList = getBusAttachment(bus);
		busVo.setAttachmentList(attachmentVoList);
//		busVo.setAttachmentList(attachmentService.getAttachmentsByXgid(busNo));//申请的附件信息
		return busVo;
	}

	/**
	 * 获取一个维保申请相关的附件信息
	 * @param bus
	 * @return
	 */
	private List<AttachmentVo> getBusAttachment(Bus bus) {
		Set<Attachment> attachmentList = bus.getAttachments();
		List<AttachmentVo> attachmentVoList = new ArrayList<>();
		if(attachmentList != null && !attachmentList.isEmpty()){
			for(Attachment attachment : attachmentList){
				AttachmentVo attachmentVo = new AttachmentVo();
				BeanUtils.copyProperties(attachment, attachmentVo);
				attachmentVoList.add(attachmentVo);
			}
		}
		return attachmentVoList;
	}

	/**
	 * 获取所有申请的节点id和名字的map
	 * @return
	 */
	private Map<String, String> getAllLcjdMapping() {
		List<Lcjdb> lcjdbList = lcjdbRepository.findBySslc("1");
		List<Lcjdb> lcjdbList2 = lcjdbRepository.findBySslc("2");
		List<Lcjdb> lcjdbList3 = lcjdbRepository.findBySslc("3");
		Map<String,String> resultMap = new HashMap<String,String>();
		for(Lcjdb lcjdb : lcjdbList){
			resultMap.put(lcjdb.getId(), lcjdb.getName());
		}
		for(Lcjdb lcjdb : lcjdbList2){
			resultMap.put(lcjdb.getId(), lcjdb.getName());
		}
		for(Lcjdb lcjdb : lcjdbList3){
			resultMap.put(lcjdb.getId(), lcjdb.getName());
		}
		resultMap.put("T", "已回填");
		resultMap.put("Y", "审核完成");
		return resultMap;
	}

	/**
	 * 从数据库中删除申请，用于未提交已保存的申请草稿
	 * @param id
	 */
	@Transactional
	public void delete(String id) {
		Bus bus = busRepository.findById(id);
		if(bus == null){
			return;
		}
		busRepository.delete(bus);
	}

	/**
	 * 
	 * @param userId
	 * @param condition
	 * @param state
	 * @return
	 */
	@Cacheable(cacheName = "BUS_CACHE")
	public List<BusVo> getBusByUserIdAndCondition(String userId, String condition, String state) {
		List<Bus> busList = null;
		if(StringUtil.isBlank(condition)){
			return new ArrayList<>();
		}
		if(StringUtil.equals(state, "wtj")){//未提交
			busList = getWtjApplications(userId,condition);
		}
		if(StringUtil.equals(state, "dsp") || StringUtil.equals(state, "dht")){//待审批||待回填
			busList = busRepository.findByApplicationStatementOrderByApplicationDateDesc(condition);
		}
		if(StringUtil.equals(state, "yht")){//已回填
			busList = busRepository.findYhtApplication(userId);
		}
		if(StringUtil.equals(state, "yth")){//已退回
			busList = busRepository.findYthApplication(userId, condition);
		}
		if(StringUtil.equals(state, "ysp")){//已审批（已审批就是根据个人取出的所以不需要再进行过滤）
			return getBusApproveYspList(userId,condition);
		}
		
		return filter(userId,condition,busList);
	}

	/**
	 * 对数据进行过滤，并设置申请的状态
	 * 1.过滤掉已经被标记为删除的维保申请
	 * 2.如果是部门内部审批时过滤掉其他部门的申请
	 * @param userId
	 * @param condition
	 * @param busList
	 * @return
	 */
	private List<BusVo> filter(String userId, String condition, List<Bus> busList) {
		List<BusVo> busVoList = new ArrayList<BusVo>();
		if(busList == null){
			return busVoList;
		}
		Map<String,String> lcjdbMap = getAllLcjdMapping();
		Lcjdb lcjd = lcjdbRepository.findOne(condition);
		User user = userRepository.findOne(userId);
		for(Bus bus : busList){
			if(StringUtil.equals(bus.getIsDeleted(), "Y")){
				continue;//过滤掉已删除的申请
			}
			if(StringUtil.equals(lcjd.getShbm(), "Y")){
				if(!sfsybm(bus.getUserName().getDepartments().iterator().next(),user.getDepartments())){
					continue;
				}
			}
			BusVo busVo = new BusVo(bus);
			convertApplicationState(lcjdbMap,busVo);
			busVoList.add(busVo);
		}
		return busVoList;
	}

	/**
	 * 维保审核状态由代码转换为对应汉字
	 * @param lcjdbMap
	 * @param busVo
	 */
	private void convertApplicationState(Map<String, String> lcjdbMap, BusVo busVo) {
		if(!StringUtil.isBlank(busVo.getApplicationStatement())){
			busVo.setApplicationStatement(lcjdbMap.get(busVo.getApplicationStatement()));
		}else{
			busVo.setApplicationStatement("");
		}
	}

	/**
	 * 
	 * @param busDepartment
	 * @param userDepartments
	 * @return true(是同一部门)<br>
	 * false(不是同一部门)
	 */
	private boolean sfsybm(Department busDepartment, Set<Department> userDepartments) {
		if(busDepartment == null || userDepartments == null){
			return false;
		}
		for(Department department : userDepartments){
			if(StringUtil.equals(busDepartment.getId(), department.getId())){
				return true;
			}
		}
		return false;
	}

	/**
	 * 对于一些退回的申请，可能会存在待审批，已审批中出现同一条记录的情况，现在通过condition
	 * （申请审核状态=condition的说明是当前用户待审批的申请，将这种申请从审批的申请列表中去除）
	 * 去除这种情况
	 * @param userId
	 * @param condition
	 * @return
	 */
	private List<BusVo> getBusApproveYspList(String userId, String condition) {
		List<BusVo> busVoList = new ArrayList<>();
		List<Bus> busList = busRepository.findYspApplication(userId, condition);
		Map<String,String> lcjdbMap = getAllLcjdMapping();
		if(busList != null && !busList.isEmpty()){
			for(Bus bus : busList){
				Set<Lcrzb> lcrzbList = bus.getLcrzSet();
				BusVo busVo = new BusVo(bus);
				setSpjg(userId,lcrzbList,busVo);
				convertApplicationState(lcjdbMap,busVo);
				busVoList.add(busVo);
			}
		}
		return busVoList;
	}

	/**
	 * 设置某人已审批申请的审批意见（某人对申请的最后一次的审批结果）
	 * @param userId
	 * @param lcrzbList
	 * @param busVo
	 */
	private void setSpjg(String userId, Set<Lcrzb> lcrzbList, BusVo busVo) {
		List<Lcrzb> lcrzbListOfUser = new ArrayList<>();
		if(lcrzbList != null && !lcrzbList.isEmpty()){
			for(Lcrzb lcrzb : lcrzbList){
				if(StringUtil.equals(lcrzb.getUser().getId(), userId)){
					lcrzbListOfUser.add(lcrzb);
				}
			}
		}
		if(!lcrzbListOfUser.isEmpty()){
			Collections.sort(lcrzbListOfUser,new Comparator<Lcrzb>(){
				@Override
				public int compare(Lcrzb c1,Lcrzb c2){
					if(c1.getClsj() == null){
						return -1;
					}
					if(c2.getClsj() == null){
						return 1;
					}
					long dif = DateUtil.getDiffSeconds(c1.getClsj(), c2.getClsj());
					return (dif > 0) ? -1 :
						((dif < 0) ? 1 : 0);
				}
			});
			Lcrzb lastLcrz = lcrzbListOfUser.get(0);
			busVo.setApproveAdvice(lastLcrz.getCljg());
		}else{
			busVo.setApproveAdvice("");
		}
	}

	/**
	 * 获取未提交的申请列表
	 * @param userId
	 * @param condition
	 * @return
	 */
	private List<Bus> getWtjApplications(String userId, String condition) {
		List<Bus> ythBusList = busRepository.findYthApplication(userId, condition);//已退回申请
		List<Bus> busList = busRepository.findByUserName_idAndApplicationStatementOrderByApplicationDateDesc(userId, condition);
		List<Bus> result = new ArrayList<Bus>();
		if(ythBusList == null || ythBusList.size() == 0){
			return busList;
		}
		Map<String,Bus> ythBusMap = new HashMap<String,Bus>();
		for(Bus bus2 : ythBusList){
			ythBusMap.put(bus2.getId(), bus2);
		}
		for(Bus bus : busList){
			if(ythBusMap.get(bus.getId()) == null){
				result.add(bus);
			}
		}
		return result;
	}

	/**
	 * 申请记录页面已审批的列表
	 * @param useId
	 * @return
	 */
	@Cacheable(cacheName = "BUS_CACHE")
	public List<BusVo> getApplicationRecordYspList(String userId) {
		List<BusVo> busVoList = new ArrayList<BusVo>();
		List<Bus> yspList = busRepository.findByUserName_idAndApplicationStatementOrderByApplicationDateDesc(userId, "Y");
		List<Bus> yhtList = busRepository.findByUserName_idAndApplicationStatementOrderByApplicationDateDesc(userId, "T");
		if(yspList != null){
			for(Bus bus1 : yspList){
				BusVo busVo = new BusVo(bus1);
				busVo.setApplicationStatement("已审批");
				busVoList.add(busVo);
			}
		}
		if(yhtList != null){
			for(Bus bus : yhtList){
				BusVo busVo = new BusVo(bus);
				busVo.setApplicationStatement("已回填");
				busVoList.add(busVo);
			}
		}
		return busVoList;
	}

	/**
	 * 申请记录页面未审批的申请
	 * @param userId
	 * @param condition
	 * @return
	 */
	@Cacheable(cacheName = "BUS_CACHE")
	public List<BusVo> getApplicationRecordWspList(String userId, String condition) {
		List<BusVo> busVoList = new ArrayList<BusVo>();
		List<Bus> wspList = busRepository.findApplicationRecordWspList(userId, condition);
		if(wspList != null && wspList.size() > 0){
			for(Bus bus : wspList){
				BusVo busVo = new BusVo(bus);
				busVo.setApplicationStatement("待审批");
				busVoList.add(busVo);
			}
		}
		return busVoList;
	}

	/**
	 * 申请审核
	 * @param cljg 处理结果
	 * @param message
	 * @param clnrid
	 * @param clnrfl
	 */
	@Transactional
	@TriggersRemove(cacheName = { "BUS_CACHE" },removeAll = true)
	public void saveBusLcrz(String cljg, String message, String clnrid, String clnrfl) {
		BusVo busVo = getBusById(clnrid);
		String nextCondition;//申请的下一个状态，根据是否被退回确定
		String curCondition = busVo.getApplicationStatement();
		String isReturned = "N";//申请是否被退回
		//添加流程日志
		String lcrzId = lcrzbService.save(new LcrzbVo(cljg,message), clnrid, clnrfl, curCondition);
		bindBusWithLcrz(clnrid,lcrzId);
		//处理意见“不通过”，并且不是法务审核就是退回
		if(StringUtil.equals(cljg, "不通过") && !StringUtil.equals(curCondition, "3")){
			isReturned = "Y";
			nextCondition = lcService.getThCondition(busVo.getLcbs(), curCondition);
			lcrzbService.setLcrzSfxs(clnrid, busVo.getLcbs(), nextCondition);
		}else{
			//修改申请状态
			nextCondition = lcService.getNextCondition(busVo.getLcbs(), curCondition);
		}
		
		if(!StringUtil.isBlank(nextCondition)){
			busVo.setApplicationStatement(nextCondition);
			busVo.setIsReturned(isReturned);
			updateApplication(busVo,null);
		}
	}
	
	/**
	 * 更新车辆编号
	 * @param id 车辆id
	 * @param busBh 车辆编号
	 */
	public void updateBusBh(String id,String busBh){
		busRepository.updateBusBh(id,busBh);
	}

	/**
	 * 判断当前要使用的车辆编号是否唯一
	 * @param busBh
	 * @return true 车辆编号是唯一的<br>
	 * false 车辆编号已经存在（不唯一）
	 */
	public boolean isBusBhUnique(String busBh) {
		if(StringUtil.isBlank(busBh)){
			throw new BaseAppException("要验证的车辆编号是否为空？");
		}
		if(busRepository.findByBh(busBh) == null){
			return true;
		}
		return false;
	}
	
	/**
	 * 查询申请
	 * @param busNo 车牌号
	 * @param busBh 车辆编号
	 * @param startTime 开始时间（搜索的时间段，以申请时间为准）
	 * @param endTime 结束时间
	 * @param applicationStatement 申请状态（0：全部，1：待审批，2：已审批，3：已回填）
	 * @param userName 驾驶员/申请人
	 * @param xgryId 相关人员ID（用于查询个人相关的申请）
	 * @return
	 */
	@Cacheable(cacheName = "BUS_CACHE")
	public List<BusVo> searchBus(final String busNo, final String busBh, final Date startTime,final Date endTime,final String applicationStatement,final String userName,final String xgryId){
		List<BusVo> busVoList = new ArrayList<BusVo>();
		List<Bus> busList = busRepository.findAll(new Specification<Bus>(){
			@Override
			public Predicate toPredicate(Root<Bus> root,CriteriaQuery<?> query,CriteriaBuilder cb){
				List<Predicate> list = new ArrayList<Predicate>();
				//车牌号
				if(!StringUtil.isBlank(busNo)){
					list.add(cb.like(root.get("busNo").as(String.class),"%" + busNo + "%" ));
				}
				//车辆编号
				if(!StringUtil.isBlank(busBh)){
					list.add(cb.like(root.get("bh").as(String.class), "%" + busBh + "%" ));
				}
				//申请状态
				if(StringUtil.equals(applicationStatement, "1")){
					list.add(cb.notEqual(root.get("applicationStatement").as(String.class),"Y"));
					list.add(cb.notEqual(root.get("applicationStatement").as(String.class),"T"));
				}
				if(StringUtil.equals(applicationStatement, "2")){
					list.add(cb.equal(root.get("applicationStatement").as(String.class), "Y"));
				}
				if(StringUtil.equals(applicationStatement, "3")){
					list.add(cb.equal(root.get("applicationStatement").as(String.class), "T"));
				}
				
				//申请时间（时间段内的申请）
				if(startTime != null && endTime != null){
					list.add(cb.between(root.get("applicationDate").as(Date.class), startTime, endTime));
				}
				//申请人（发起人）
				if(!StringUtil.isBlank(userName)){
					Join<Bus,User> busUserLeftJoin = root.join(root.getModel().getSingularAttribute("userName",User.class),JoinType.LEFT);
					list.add(cb.equal(busUserLeftJoin.get("fullName").as(String.class), userName));//申请人
				}
				
				//相关的人员的ID（用于查询个人相关的合同）
				if(!StringUtil.isBlank(xgryId)){
					Join<Bus,Lcrzb> busLcrzbLeftJoin = root.joinSet("lcrzSet",JoinType.LEFT);
					list.add(cb.equal(busLcrzbLeftJoin.get("user").get("id").as(String.class), xgryId));
				}
				
				Predicate[] predicate = new Predicate[list.size()];
				Predicate psssredicate = cb.and(list.toArray(predicate));
				return psssredicate;
			}
		});
		if(busList == null){
			return busVoList;
		}
		for(Bus bus : busList){
			BusVo busVo = new BusVo(bus);
			if(StringUtil.equals(bus.getApplicationStatement(), "Y")){
				busVo.setApplicationStatement("已审批");
			}else if(StringUtil.equals(bus.getApplicationStatement(), "T")){
				busVo.setApplicationStatement("已回填");
			}else{
				busVo.setApplicationStatement("待审批");
			}
			busVoList.add(busVo);
		}
		return busVoList;
	}
}
